#include "bsp.h"
#include "gd32f1x0.h"

/* retarget the gcc's C library printf function to the USART */
#include <errno.h>
#include <sys/unistd.h> // STDOUT_FILENO, STDERR_FILENO
int _write(int file, char *data, int len)
{
	if ((file != STDOUT_FILENO) && (file != STDERR_FILENO)) {
		errno = EBADF;
		return -1;
	}

	for (int i = 0; i < len; i++) {
		usart_data_transmit(USART0, (uint8_t)data[i]);
		while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
			;
	}

	// return # of bytes written - as best we can tell
	return len;
}

// PC2 vdden
// PC3 LED1
//

#define BSP_KEY_PORT GPIOC
#define BSP_KEY_PIN GPIO_PIN_1

#define BSP_VDDEN_PORT GPIOC
#define BSP_VDDEN_PIN GPIO_PIN_2

#define BSP_LED_PORT GPIOC
#define BSP_LED_PIN GPIO_PIN_3

struct pin_map_typedef {
	uint32_t port;
	uint32_t pin;
	uint8_t mode; /* -1: not usable, 0: not set, 1: key, 2:lcd */
};

struct pin_map_typedef _bsp_keyPin = {
    BSP_KEY_PORT,
    BSP_KEY_PIN,
    1,
};

struct pin_map_typedef bsp_pin_map[] = {
    {-1, -1, -1},	    // 0 No pin 0, start from 1
    {GPIOC, GPIO_PIN_1, 0}, // 1 PC1 = Key
    {-1, -1, -1},	    // 2 GND
    {GPIOB, GPIO_PIN_0, 0}, // 3 PB0
    {GPIOB, GPIO_PIN_1, 0}, // 4 PB1
    {GPIOB, GPIO_PIN_2, 0}, // 5 PB2
    {GPIOB, GPIO_PIN_3, 0}, // 6 PB3
    {GPIOB, GPIO_PIN_4, 0}, // 7 PB4
    {GPIOB, GPIO_PIN_5, 0}, // 8 PB5
    {GPIOB, GPIO_PIN_6, 0}, // 9 PB6
    {GPIOB, GPIO_PIN_7, 0}, // 10 PB7
    {-1, -1, -1},	    // 11 NRST
    {GPIOA, GPIO_PIN_7, 0}, // 12 PA7
    {GPIOA, GPIO_PIN_6, 0}, // 13 PA6
    {GPIOA, GPIO_PIN_5, 0}, // 14 PA5
    {GPIOA, GPIO_PIN_4, 0}, // 15 PA4
    {GPIOA, GPIO_PIN_3, 0}, // 16 PA3
    {GPIOA, GPIO_PIN_2, 0}, // 17 PA2
    {GPIOA, GPIO_PIN_1, 0}, // 18 PA1
    {GPIOA, GPIO_PIN_0, 0}, // 19 PA0
    {-1, -1, -1},	    // 20 VDD
    {-1, -1, -1},	    // 21 PC0
    {-1, -1, -1},	    // 22 3V3_fix
    {-1, -1, -1},	    // 23 NC
    {-1, -1, -1},	    // 24 GND
    {-1, -1, -1},	    // 25 NC
    {-1, -1, -1},	    // 26 NC
};

void bsp_lcd_io_initial(void)
{
	// port A
	rcu_periph_clock_enable(RCU_GPIOA);

	gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
		      GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
	gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
				GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);

	// port B
	rcu_periph_clock_enable(RCU_GPIOB);

	gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
		      GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
	gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
				GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
}

void bsp_initial(void)
{
	// board util gpio
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_GPIOB);
	rcu_periph_clock_enable(RCU_GPIOC);

	gpio_mode_set(BSP_VDDEN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, BSP_VDDEN_PIN);
	gpio_output_options_set(BSP_VDDEN_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_VDDEN_PIN);

	gpio_mode_set(BSP_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, BSP_LED_PIN);
	gpio_output_options_set(BSP_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_LED_PIN);
}

void bsp_allio_low(void)
{
	for(int i = 3; i < 3+8; i++) {
		gpio_mode_set(bsp_pin_map[i].port, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, bsp_pin_map[i].pin);
	}

	for(int i = 12; i < 12+8; i++) {
		gpio_mode_set(bsp_pin_map[i].port, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, bsp_pin_map[i].pin);
	}
}

void bsp_setKeyPin(int n)
{
	_bsp_keyPin.port = bsp_pin_map[n].port;
	_bsp_keyPin.pin = bsp_pin_map[n].pin;
	_bsp_keyPin.mode = 1;

	gpio_mode_set(_bsp_keyPin.port, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, _bsp_keyPin.pin);
}

int bsp_getKey(void)
{
	if (gpio_input_bit_get(_bsp_keyPin.port, _bsp_keyPin.pin) != RESET) {
		return 1;
	} else {
		return 0;
	}
}

void bsp_setLed(int state)
{
	if (state != 0) {
		gpio_bit_write(BSP_LED_PORT, BSP_LED_PIN, RESET);
	} else {
		gpio_bit_write(BSP_LED_PORT, BSP_LED_PIN, SET);
	}
}

void bsp_toggleLed(void)
{
	FlagStatus r = gpio_output_bit_get(BSP_LED_PORT, BSP_LED_PIN);
	gpio_bit_write(BSP_LED_PORT, BSP_LED_PIN, !r);
}

void bsp_setVdd(int state)
{
	if (state != 0) {
		gpio_bit_write(BSP_VDDEN_PORT, BSP_VDDEN_PIN, SET);
	} else {
		gpio_bit_write(BSP_VDDEN_PORT, BSP_VDDEN_PIN, RESET);
	}
}

void bsp_pinOutPP(int n, int pulltype)
{
	gpio_mode_set(bsp_pin_map[n].port, GPIO_MODE_OUTPUT, PUD_PUPD(pulltype), bsp_pin_map[n].pin);
	gpio_output_options_set(bsp_pin_map[n].port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, bsp_pin_map[n].pin);
}

void bsp_pinOutOD(int n, int pulltype)
{
	gpio_mode_set(bsp_pin_map[n].port, GPIO_MODE_OUTPUT, PUD_PUPD(pulltype), bsp_pin_map[n].pin);
	gpio_output_options_set(bsp_pin_map[n].port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, bsp_pin_map[n].pin);
}

void bsp_pinIn(int n, int pulltype)
{
	gpio_mode_set(bsp_pin_map[n].port, GPIO_MODE_INPUT, PUD_PUPD(pulltype), bsp_pin_map[n].pin);
}

inline void bsp_setPin(int n, int state)
{
	if ((bsp_pin_map[n].port == -1) || (bsp_pin_map[n].pin == -1)) {
		return;
	}

	gpio_bit_write(bsp_pin_map[n].port, bsp_pin_map[n].pin, state ? SET : RESET);
}

inline int bsp_getPin(int n)
{
	if ((bsp_pin_map[n].port == -1) || (bsp_pin_map[n].pin == -1)) {
		return -1;
	}

	if (gpio_input_bit_get(bsp_pin_map[n].port, bsp_pin_map[n].pin) != RESET) {
		return 1;
	} else {
		return 0;
	}
}

void bsp_sendChar(char c)
{
	usart_data_transmit(USART0, c);
}

void bsp_sendString(char *s)
{
	char *ls = s;
	while (*ls) {
		usart_data_transmit(USART0, *ls--);
	}
}

char bsp_getChar(void)
{
	return (char)usart_data_receive(USART0);
}

/**
 * @brief check recive complet flag
 *
 * @return 1:flag set, 0:no flag
 */
int bsp_getRxcpltFlag(void)
{
	if (usart_flag_get(USART0, USART_FLAG_RBNE) != RESET) {
		return 1;
	} else {
		return 0;
	}
}
